using System;
using Tycho.Runtime;

namespace Tycho.Native {
    public static class NativeObjectConversion {
        public static object ConvertToNative (AnyObject runtimeObject) {
            Type runtimeType = runtimeObject.GetType ();
            if (runtimeType.GetGenericTypeDefinition () == typeof (ValueObject<>)) {
                return runtimeType.GetProperty ("Value").GetValue (runtimeObject, null);
            } else if (runtimeObject is NativeObject) {
                return ((NativeObject) runtimeObject).Object;
            } else if (runtimeObject is NullObject) {
                return null;
            } else {
                throw new TychoException (String.Format ("object `{0}' cannot be converted", runtimeObject));
            }
        }

        public static AnyObject ConvertToRuntime (object nativeObject) {
            if (nativeObject == null) {
                return RuntimeModule.Null;
            } else {
                Type nativeObjectType = nativeObject.GetType ();
                AnyObject valuePrototype = GetValueTypePrototype (nativeObjectType);

                if (valuePrototype != null) {
                    Type valueType = typeof (ValueObject<>).MakeGenericType (new Type[] { nativeObjectType });
                    return (AnyObject) Activator.CreateInstance (valueType, valuePrototype, nativeObject);
                } else if (nativeObjectType == typeof (Type)) {
                    return NativeTypeCache.GetNativeType (nativeObjectType);
                } else {
                    return (AnyObject) Activator.CreateInstance (typeof (NativeObject), nativeObject, NativeTypeCache.GetNativeType (nativeObjectType));
                }
            }
        }

        public static AnyObject GetValueTypePrototype (Type valueType) {
            if (valueType == typeof (Boolean) || valueType.IsSubclassOf (typeof (Boolean))) {
                return RuntimeModule.Boolean;
            } else if (valueType == typeof (Int32) || valueType.IsSubclassOf (typeof (Int32))) {
                return RuntimeModule.Integer;
            } else if (valueType == typeof (Double) || valueType.IsSubclassOf (typeof (Double))) {
                return RuntimeModule.Real;
            } else if (valueType == typeof (String) || valueType.IsSubclassOf (typeof (String))) {
                return RuntimeModule.String;
            } else if (valueType == typeof (DateTime) || valueType.IsSubclassOf (typeof (DateTime))) {
                return RuntimeModule.DateTime;
            } else {
                return null;
            }
        }
    }
}